from queue import Queue
from threading import Thread, current_thread
from time import sleep
import random
import threading

# 创建一个队列
queue = Queue(5)
# 访问共有数据，加互斥锁
lock = threading.Lock()


# 定义生产者线程(通过继承重新定义子线程的run方法)
class ProducerTherad(Thread):

    def __init__(self):
        Thread.__init__(self)
        # 定义线程退出标志
        self.__stop_producer = threading.Event()
        # 将event的标志设置为False
        self.__stop_producer.clear()

    def run(self):
        name = current_thread().getName()
        nums = range(100)
        # 表明被其修饰的变量是全局变量，python 解释器去函数的 __globals__ 字典变量中寻找
        global queue

        while not self.__stop_producer.is_set():
            # 返回一个列表，元组或字符串的随机项
            num = random.choice(nums)
            # 将生成的数据入队
            queue.put(num)
            print('producer %s produced %s' % (name, num))
            duration = random.randint(1, 3)
            # sleep(duration * 0.3)
            # 阻塞一段时间，调用set后唤醒或超时继续执行
            self.__stop_producer.wait(duration * 0.3)
            print('producer %s sleeped %s second' % (name, duration))

    def stop(self):
        # 将event的标志设置为True
        self.__stop_producer.set()


# 定义消费者线程
class ConsumerThread(Thread):

    def __init__(self):
        Thread.__init__(self)
        # 定义线程退出标志
        self.__stop_consumer = threading.Event()
        # 将event的标志设置为False
        self.__stop_consumer.clear()

    def run(self):
        name = current_thread().getName()
        global queue

        while not self.__stop_consumer.is_set():
            # 从队列中取出一个数据
            nums = queue.get()
            # 向队列发送一个信号，每task_done一次 就从队列里删掉一个元素，在最后join的时候根据队列长度是否为零来判断队列是否结束
            queue.task_done()
            print('consumer %s consumed %s' % (name, nums))
            duration = random.randint(1, 3)
            # sleep(duration * 0.3)
            # 阻塞一段时间，调用set后唤醒或超时继续执行
            self.__stop_consumer.wait(duration * 0.3)
            print('consumer %s sleeped %s' % (name, duration))

    def stop(self):
        # 将event的标志设置为True
        self.__stop_consumer.set()


# 主线程开始
print("%s start" % current_thread().getName())

# 创建2个生产者线程
p = []

for i in range(1, 3):
    p.append(ProducerTherad())

# 启动
for pp in p:
    pp.start()
    sleep(0.0001)


# 创建3个消费者线程
c = []

for i in range(1, 4):
    c.append(ConsumerThread())

# 启动
for cc in c:
    cc.start()
    sleep(0.0001)


# 主线程睡眠
sleep(1)

# 消费者线程停止
for cc in c:
    cc.stop()
    # 等待消费者线程停止
    cc.join()

# 生产者线程停止
for pp in p:
    pp.stop()
    # 等待生产者线程停止
    pp.join()


# 主线程结束
print("%s end" % current_thread().getName())

